#include "NetServer.h"

//////////////////////////////////////////////////////////////////////////
// Client_Session
client_session::client_session( 
							   INetNotify* pNetNotify, 
							   CLogModule* pLogModule, 
							   boost::asio::io_service& io_service_ ,
							   client_holder& client_holder_,
							   NetIDGenerator& net_id_
							   )
							   : m_socket_(io_service_)
							   , m_io_service_(io_service_)
							   , m_pNetNotify(pNetNotify)
							   , m_pLogModule(pLogModule)
							   , m_client_holder(client_holder_)
							   , m_NetIDGenerator(net_id_)
{
	m_ullClientID = m_NetIDGenerator.get_id();
}

client_session::~client_session( void )
{

}

void client_session::Start( void )
{
 	m_pLogModule->WriteLog(LOG_DEBUG,"ClientID = %d ,enter Client_session::Start.",m_socket_.native_handle());
 	m_client_holder.join(shared_from_this());
 	m_socket_.async_read_some(boost::asio::buffer(data_),
 		boost::bind(&client_session::handle_read,this,boost::asio::placeholders::error,
 		boost::asio::placeholders::bytes_transferred));
}

void client_session::handle_read(const boost::system::error_code& error,const size_t bytes_transferred)
{
 	if (!error)
 	{
 		m_pNetNotify->OnReceiveData(m_ullClientID, data_.c_array(), bytes_transferred);
 		m_socket_.async_read_some(boost::asio::buffer(data_),
 			boost::bind(&client_session::handle_read,this,boost::asio::placeholders::error,
 			boost::asio::placeholders::bytes_transferred));
 	} 
 	else
 	{
		if (error.value() != boost::asio::error::eof)
 			m_pNetNotify->OnErrorOccurred(m_ullClientID, error.value(),error.message().c_str());
		Close();
 	}
}

void client_session::Close( void )
{
	m_io_service_.post(boost::bind(&client_session::handle_close,this));
}

void client_session::handle_close( void )
{
 	m_socket_.close();
 	m_pNetNotify->OnClose(m_ullClientID);
 	m_client_holder.leave(m_ullClientID);
}

void client_session::SendData( const char* pData, unsigned int unDataLength )
{
 	if (pData == NULL || unDataLength == 0) return;
 	m_socket_.async_send(boost::asio::buffer(pData,unDataLength),
 		boost::bind(&client_session::handle_write,this,boost::asio::placeholders::error,
 		boost::asio::placeholders::bytes_transferred));
}

void client_session::handle_write(const boost::system::error_code& error,const size_t bytes_transferred)
{
 	if (!error)
 	{
 		m_pNetNotify->OnSendData(m_ullClientID,bytes_transferred);
 	}
 	else
 	{
		if (error.value() != boost::asio::error::eof)
 			m_pNetNotify->OnErrorOccurred(m_ullClientID, error.value(), error.message().c_str());
		Close();
 	}
}

////////////////////////////////////////////////////////////////////////
CNetServer::CNetServer(
					   INetNotify* pNetNotify, 
					   CLogModule* pLogModule, 
					   boost::shared_ptr<io_service_pool> io_service_pool,
					   NetIDGenerator& net_id_
					   )
					   : m_io_service_pool_ptr(io_service_pool)
					   , m_pNetNotify(pNetNotify)
					   , m_pLogModule(pLogModule)
					   , m_NetIDGenerator(net_id_	)
{
	
}

CNetServer::~CNetServer(void)
{
	if (m_acceptor_ptr->is_open()) Stop_Service();
}

void CNetServer::SetServerPort( unsigned short nPort )
{
	try
	{
		boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(),nPort);
		m_acceptor_ptr.reset(new boost::asio::ip::tcp::acceptor(m_io_service_pool_ptr->Get_io_service(),endpoint));
	}
	catch(boost::system::system_error& e)
	{
		m_pNetNotify->OnErrorOccurred(0,e.code().value(),e.code().message().c_str());
	}
}
void CNetServer::Start_Service( void )
{
	client_session_ptr new_client(new client_session(m_pNetNotify,m_pLogModule,m_io_service_pool_ptr->Get_io_service(),m_client_hodler,m_NetIDGenerator));
	if (m_acceptor_ptr->is_open())
		m_acceptor_ptr->async_accept(new_client->get_socket(),
			boost::bind(&CNetServer::handle_accept,this,new_client,boost::asio::placeholders::error));
}

void CNetServer::handle_accept( client_session_ptr new_client,const boost::system::error_code& error )
{
	if (!error)
	{
		new_client->Start();
		m_pNetNotify->OnConnect(new_client->GetClientID(),new_client->get_socket().remote_endpoint().address().to_string().c_str(),
			new_client->get_socket().remote_endpoint().port());
		Start_Service();
	} 
	else
	{
		m_pNetNotify->OnErrorOccurred(0,error.value(),error.message().c_str());
	}
}

void CNetServer::CloseClient( unsigned __int64 nClientID )
{
	client_session_ptr client_ptr = m_client_hodler.get_client(nClientID);
	if (client_ptr) client_ptr->Close();
}

void CNetServer::SendData( unsigned __int64 nClientID, const char* pData, unsigned int unDataLength )
{
	client_session_ptr client_ptr = m_client_hodler.get_client(nClientID);
	if (client_ptr)
	{
		client_ptr->SendData(pData,unDataLength);
	}
}

void CNetServer::Stop_Service( void )
{
	m_acceptor_ptr->close();
	m_client_hodler.stop_all();
}

void CNetServer::KickAllClient( void )
{
	m_client_hodler.stop_all();
}
